package com.ocean.web.util.rwdata;

import com.ocean.system.domain.SeaTempNcMetadata;
import ucar.ma2.Array;
import ucar.nc2.Attribute;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 西北太平洋海温 NC 文件元数据读取工具（适配 netcdfAll-5.4.1 + 目标文件结构）
 * 要素名称elements返回短名称（分号隔开），沿用 SeaTempNcMetadata 实体类
 */
public class GlobalXBTSstNcReader_5_4_1 {

    // 时间格式工具（GMT 适配文件时间单位，CST 用于最终显示）
    private static final SimpleDateFormat GMT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat CST_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat FILENAME_TIME_FORMAT = new SimpleDateFormat("yyyyMMddHH");
    static {
        GMT_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
        CST_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 转换为中国标准时间
        FILENAME_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+8"));
    }

    // 文件名正则（匹配：起报时间yyyyMMddHH、预报时效xxxh）
    private static final Pattern FILENAME_PATTERN = Pattern.compile(
            "^NMF_BEN_OSMTSCB_NWPACDT_(\\d{10})_(\\d{3}h)_SWT\\.nc$"
    );

    // 文件time变量基准时间（从units属性提取：1990-01-01 00:00:00 GMT）
    private static final Date BASE_TIME;
    static {
        try {
            BASE_TIME = GMT_FORMAT.parse("1990-01-01 00:00:00");
        } catch (ParseException e) {
            throw new RuntimeException("基准时间初始化失败", e);
        }
    }

    /**
     * 核心方法：读取目标NC文件元数据，返回SeaTempNcMetadata实体
     * @param ncFilePath NC文件路径（本地文件）
     * @return SeaTempNcMetadata 元数据实体（要素为短名称）
     * @throws IOException NC文件读取异常
     */
    public SeaTempNcMetadata readNwPacificMetadata(String ncFilePath) throws IOException {
        // 前置校验：路径非空+文件存在
        if (ncFilePath == null || ncFilePath.trim().isEmpty()) {
            throw new IllegalArgumentException("NC文件路径不能为空！");
        }
        File ncFile = new File(ncFilePath);
        if (!ncFile.exists() || !ncFile.isFile()) {
            throw new IOException("NC文件不存在或非法：" + ncFilePath);
        }

        String ncFileName = extractFileName(ncFilePath);
        FileNameParseResult parseResult = parseFileName(ncFileName);

        try (NetcdfFile ncFileObj = NetcdfFile.open(ncFilePath)) {
            // 1. NC文件名
            // 2. 来源（优先读文件属性，默认西北太平洋智能网格）
            String source = getGlobalAttrValue(ncFileObj, "institution", "西北太平洋智能网格海温预报系统");
            if ("西北太平洋智能网格海温预报系统".equals(source)) {
                source = getGlobalAttrValue(ncFileObj, "source", "西北太平洋智能网格海温预报系统");
            }

            // 3. 类型（西北太平洋海表温度）
            String type = "西北太平洋海表温度（SWT）";

            // 4. 起报时间（文件名优先，失败则从time变量计算）
            String forecastBaseTime = parseResult.getBaseTime();
            if ("解析失败".equals(forecastBaseTime)) {
                forecastBaseTime = calculateBaseTimeFromTimeVar(ncFileObj);
            }

            // 5. 预报时效（文件名168h优先，失败则从time变量计算）
            String forecastLeadTime = parseResult.getLeadTime();
            if ("解析失败".equals(forecastLeadTime)) {
                forecastLeadTime = calculateLeadTimeFromTimeVar(ncFileObj);
            }

            // 6. 预报频次（从time变量时次间隔计算）
            String forecastFreq = calculateForecastFreq(ncFileObj);

            // 7. 覆盖范围（解析lat/lon实际范围）
            String coverage = parseCoverage(ncFileObj);

            // 8. 空间分辨率（计算lat/lon格点间隔）
            String spatialRes = calculateSpatialResolution(ncFileObj);

            // 9. 要素名称elements（短名称，分号隔开）- 核心修改
            String elements = getSeaTempShortNames(ncFileObj);

            // 构建实体返回
            return new SeaTempNcMetadata(
                    ncFileName,
                    source,
                    type,
                    forecastBaseTime,
                    forecastLeadTime,
                    forecastFreq,
                    coverage,
                    spatialRes,
                    elements
            );
        }
    }

    // ---------------------- 核心新增方法：提取要素短名称（分号隔开）----------------------
    /**
     * 提取西北太平洋海温要素短名称（适配temp、sst等变量，纯短名称，分号隔开）
     * 适配：变量名含下划线则取第一部分（如 temp_01 → temp），自动去重
     */
    private String getSeaTempShortNames(NetcdfFile ncFile) {
        // 西北太平洋海温常见变量名（优先temp，适配目标文件结构）
        String[] targetVarNames = {"temp", "sst", "tos", "sea_surface_temperature", "temperature_at_sea_surface"};
        StringBuilder shortNames = new StringBuilder();

        for (String varName : targetVarNames) {
            Variable var = ncFile.findVariable(varName);
            if (var == null) {
                continue; // 变量不存在则跳过，避免空指针
            }

            // 提取短名称：优先取变量的shortName，无则用变量名
            String shortName = var.getShortName() != null ? var.getShortName() : varName;
            // 处理下划线后缀（如 "temp_10m" → "temp"、"sst_nwpac" → "sst"）
            if (shortName.contains("_")) {
                shortName = shortName.split("_")[0].trim();
            }
            // 避免重复添加同一短名称
            if (shortNames.indexOf(shortName) == -1) {
                shortNames.append(shortName).append(";");
            }
        }

        // 移除最后一个分号，为空则返回默认值
        if (shortNames.length() > 0) {
            return shortNames.substring(0, shortNames.length() - 1);
        } else {
            return "未识别到要素短名称";
        }
    }

    // ---------------------- 原有西北太平洋专属方法（保持不变）----------------------
    /**
     * 提取文件名
     */
    private String extractFileName(String filePath) {
        if (filePath == null || filePath.isEmpty()) {
            return "unknown.nc";
        }
        filePath = filePath.replace("\\", "/");
        int lastSlashIndex = filePath.lastIndexOf("/");
        return lastSlashIndex == -1 ? filePath : filePath.substring(lastSlashIndex + 1);
    }

    /**
     * 解析文件名：起报时间、预报时效
     */
    private FileNameParseResult parseFileName(String fileName) {
        Matcher matcher = FILENAME_PATTERN.matcher(fileName);
        if (!matcher.matches()) {
            return new FileNameParseResult("解析失败", "解析失败");
        }

        try {
            // 解析起报时间（2025090812 → 2025-09-08 12:00:00 CST）
            String baseTimeStr = matcher.group(1);
            Date baseTime = FILENAME_TIME_FORMAT.parse(baseTimeStr);
            String formattedBaseTime = CST_FORMAT.format(baseTime);

            // 解析预报时效（168h → 168小时）
            String leadTimeStr = matcher.group(2);
            String formattedLeadTime = leadTimeStr.replace("h", "小时");

            return new FileNameParseResult(formattedBaseTime, formattedLeadTime);
        } catch (ParseException e) {
            return new FileNameParseResult("解析失败", "解析失败");
        }
    }

    /**
     * 从time变量计算起报时间（time[0]为基准时间偏移量）
     */
    private String calculateBaseTimeFromTimeVar(NetcdfFile ncFile) {
        Variable timeVar = ncFile.findVariable("time");
        if (timeVar == null) {
            return "未知";
        }

        try {
            // 读取time变量第一个值（起报时间的小时偏移量）
            Array timeArray = timeVar.read(new int[]{0}, new int[]{1});
            double baseTimeHours = timeArray.getDouble(0);

            // 计算实际时间（基准时间 + 偏移小时数）
            long baseTimeMs = BASE_TIME.getTime() + (long) (baseTimeHours * 60 * 60 * 1000);
            Date baseTime = new Date(baseTimeMs);

            // 转换为CST格式返回
            return CST_FORMAT.format(baseTime);
        } catch (Exception e) {
            return "解析失败";
        }
    }

    /**
     * 从time变量计算预报时效（最后一个时次 - 第一个时次）
     */
    private String calculateLeadTimeFromTimeVar(NetcdfFile ncFile) {
        Variable timeVar = ncFile.findVariable("time");
        if (timeVar == null) {
            return "未知";
        }

        try {
            Array timeArray = timeVar.read();
            int timeSize = (int) timeArray.getSize();
            if (timeSize < 2) {
                return "0小时（分析场）";
            }

            double baseHours = timeArray.getDouble(0);
            double lastHours = timeArray.getDouble(timeSize - 1);
            double totalLeadHours = lastHours - baseHours;

            return String.format("%.0f小时（%d个时次）", totalLeadHours, timeSize);
        } catch (Exception e) {
            return "解析失败";
        }
    }

    /**
     * 计算预报频次（time变量相邻时次间隔）
     */
    private String calculateForecastFreq(NetcdfFile ncFile) {
        Variable timeVar = ncFile.findVariable("time");
        if (timeVar == null) {
            return "未知";
        }

        try {
            Array timeArray = timeVar.read();
            int timeSize = (int) timeArray.getSize();
            if (timeSize < 2) {
                return "单次（分析场）";
            }

            // 计算前两个时次的间隔（默认等间隔）
            double intervalHours = timeArray.getDouble(1) - timeArray.getDouble(0);

            if (intervalHours == 1) {
                return "每1小时1次";
            } else if (intervalHours == 3) {
                return "每3小时1次";
            } else if (intervalHours == 6) {
                return "每6小时1次";
            } else if (intervalHours == 12) {
                return "每12小时1次";
            } else if (intervalHours == 24) {
                return "每日1次";
            } else {
                return String.format("每%.0f小时1次", intervalHours);
            }
        } catch (Exception e) {
            return "解析失败";
        }
    }

    /**
     * 解析覆盖范围（lat/lon的min/max值）
     */
    private String parseCoverage(NetcdfFile ncFile) {
        String latRange = getLatLonRange(ncFile, "lat");
        String lonRange = getLatLonRange(ncFile, "lon");

        return String.format("西北太平洋海域（纬度：%s，经度：%s）", latRange, lonRange);
    }

    /**
     * 获取经/纬度范围（遍历数组取真实min/max）
     */
    private String getLatLonRange(NetcdfFile ncFile, String varName) {
        Variable var = ncFile.findVariable(varName);
        if (var == null) {
            return "未知";
        }

        try {
            Array array = var.read();
            double min = Double.MAX_VALUE;
            double max = Double.MIN_VALUE;

            // 遍历所有格点，避免维度递增/递减影响
            for (int i = 0; i < array.getSize(); i++) {
                double val = array.getDouble(i);
                if (val < min) min = val;
                if (val > max) max = val;
            }

            // 补充单位说明（degree_north/degree_east）
            String unit = getVarAttrValue(var, "units", "");
            if ("degree_north".equals(unit)) {
                return String.format("%.2f°N - %.2f°N", min, max);
            } else if ("degree_east".equals(unit)) {
                return String.format("%.2f°E - %.2f°E", min, max);
            } else {
                return String.format("%.2f - %.2f（%s）", min, max, unit);
            }
        } catch (Exception e) {
            return "解析失败";
        }
    }

    /**
     * 计算空间分辨率（经/纬度相邻格点间隔）
     */
    private String calculateSpatialResolution(NetcdfFile ncFile) {
        String latRes = getDimResolution(ncFile, "lat");
        String lonRes = getDimResolution(ncFile, "lon");

        return String.format("纬度：%s，经度：%s", latRes, lonRes);
    }

    /**
     * 计算单个维度的分辨率
     */
    private String getDimResolution(NetcdfFile ncFile, String varName) {
        Variable var = ncFile.findVariable(varName);
        if (var == null) {
            return "未知";
        }

        try {
            Array array = var.read();
            int size = (int) array.getSize();
            if (size < 2) {
                return "未知";
            }

            // 计算相邻格点间隔（取前两个值的绝对值）
            double res = Math.abs(array.getDouble(1) - array.getDouble(0));
            return String.format("%.4f°", res); // 保留4位小数，适配高精度网格
        } catch (Exception e) {
            return "解析失败";
        }
    }

    /**
     * 读取全局属性值
     */
    private String getGlobalAttrValue(NetcdfFile ncFile, String attrName, String defaultValue) {
        Attribute attr = ncFile.findGlobalAttribute(attrName);
        return attr != null ? attr.getStringValue().trim() : defaultValue;
    }

    /**
     * 读取变量属性值
     */
    private String getVarAttrValue(Variable var, String attrName, String defaultValue) {
        Attribute attr = var.findAttribute(attrName);
        return attr != null ? attr.getStringValue().trim() : defaultValue;
    }

    /**
     * 内部辅助类：存储文件名解析结果
     */
    private static class FileNameParseResult {
        private final String baseTime;
        private final String leadTime;

        public FileNameParseResult(String baseTime, String leadTime) {
            this.baseTime = baseTime;
            this.leadTime = leadTime;
        }

        public String getBaseTime() {
            return baseTime;
        }

        public String getLeadTime() {
            return leadTime;
        }
    }

    // 测试方法（验证短名称输出）
    public static void main(String[] args) {
        // 替换为你的西北太平洋海温NC文件路径
        String ncFilePath = "E:\\项目资料备份\\新云平台文件\\2025工作\\样例数据-检验\\西北太海温\\NMF_BEN_OSMTSCB_NWPACDT_2025111812_168h_SWT.nc";
        GlobalXBTSstNcReader_5_4_1 reader = new GlobalXBTSstNcReader_5_4_1();

        try {
            // 读取元数据，返回SeaTempNcMetadata实体
            SeaTempNcMetadata metadata = reader.readNwPacificMetadata(ncFilePath);

            // 打印结果（沿用实体类toString格式，要素为短名称）
            System.out.println("西北太平洋海温 NC 文件元数据：");
            System.out.println(metadata);

            // 结构化获取字段示例（要素短名称）
            System.out.println("\n单独获取字段：");
            System.out.println("起报时间：" + metadata.getForecastBaseTime());
            System.out.println("空间分辨率：" + metadata.getSpatialRes());
            System.out.println("要素名称elements（短名称）：" + metadata.getElements());
        } catch (IOException e) {
            System.err.println("读取失败：" + e.getMessage());
            e.printStackTrace();
        }
    }
}